package org.ands.client.bom;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.ands.apps.PropertyHelper;
import org.ands.data.Contents;
import org.ands.data.IClientContentsRetriever;
import org.ands.data.ISpatialRetriever;
import org.ands.xml.DOMHelper;
import org.ands.xml.DOMHelperFromFile;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class ContentsRetrieverBOM implements IClientContentsRetriever, ISpatialRetriever{
	
	private static final Map<String, String> s_regionIdMap;
    static
    {
    	s_regionIdMap = new HashMap<String, String>();
    	s_regionIdMap.put("North East Coast", "AWRA_North_East_Coast");
    	s_regionIdMap.put("South East Coast (Victoria)", "AWRA_South_East_Coast_Vic");
    	s_regionIdMap.put("Tasmania", "AWRA_Tasmania");
    	s_regionIdMap.put("MurrayDarling Basin", "AWRA_Murray_Darling_Basin");
    	s_regionIdMap.put("South Australian Gulf", "AWRA_South_Australian_Gulf");
    	s_regionIdMap.put("South Western Plateau", "AWRA_South_Western_Plateau");
    	s_regionIdMap.put("South West Coast", "AWRA_South_West_Coast");
    	s_regionIdMap.put("PilbaraGascoyne", "AWRA_Pilbara_Gascoyne");
    	s_regionIdMap.put("North Western Plateau", "AWRA_North_Western_Plateau");
    	s_regionIdMap.put("Tanami  Timor Sea Coast", "AWRA_Tanami_Timor");
    	s_regionIdMap.put("Lake Eyre Basin", "AWRA_Lake_Eyre_Basin");
    	s_regionIdMap.put("Carpentaria Coast", "AWRA_Carpentaria_Coast");
    	s_regionIdMap.put("South East Coast (NSW)", "AWRA_South_East_Coast");
    }
    
    private static final Map<String, String> s_regionNumberIdMap;
    static
    {
    	s_regionNumberIdMap = new HashMap<String, String>();
    	s_regionNumberIdMap.put("Region1", "AWRA_North_East_Coast");
    	s_regionNumberIdMap.put("Region2b", "AWRA_South_East_Coast_Vic");
    	s_regionNumberIdMap.put("Region3", "AWRA_Tasmania");
    	s_regionNumberIdMap.put("Region4", "AWRA_Murray_Darling_Basin");
    	s_regionNumberIdMap.put("Region5", "AWRA_South_Australian_Gulf");
    	s_regionNumberIdMap.put("Region6", "AWRA_South_Western_Plateau");
    	s_regionNumberIdMap.put("Region7", "AWRA_South_West_Coast");
    	s_regionNumberIdMap.put("Region8", "AWRA_Pilbara_Gascoyne");
    	s_regionNumberIdMap.put("Region9", "AWRA_North_Western_Plateau");
    	s_regionNumberIdMap.put("Region10", "AWRA_Tanami_Timor");
    	s_regionNumberIdMap.put("Region11", "AWRA_Lake_Eyre_Basin");
    	s_regionNumberIdMap.put("Region12", "AWRA_Carpentaria_Coast");
    	s_regionNumberIdMap.put("Region2a", "AWRA_South_East_Coast");
    }


	@Override
	public Map<Integer, List<Contents>> getXmlContentsFromClient(
			PropertyHelper propertyHelper) throws Exception {
		// TODO Auto-generated method stub
		
		assert(false);
		throw new Exception("Not implemented");
	}

	@Override
	public String getOutFileFromConfig(PropertyHelper propertyHelper)
			throws Exception {
		// TODO Auto-generated method stub
		assert(false);
		throw new Exception("Not implemented");
	}
	
	/**
	 * Gets the spatial xml rif-cs from a kml file contents.
	 *
	 * @return the xml contents
	 * @throws Exception the exception
	 */
	@Override
	public Map<Integer, List<Contents>> getSpatialFromKML(final String kmlFileName, final int fileCount) throws Exception{
		
		DOMHelperFromFile domHelper = new DOMHelperFromFile(kmlFileName);
		
		String regionNumberString = getRegionFromFileName(kmlFileName);
		String id = getIdFromRegionNumber(regionNumberString);
		assert(id != null);
		assert(!id.isEmpty());
		
		Map<Integer, List<Contents>> xmlContentsSpatialPerKML = new HashMap<Integer, List<Contents>>();
		List<Contents> contentsList = new ArrayList<Contents>();
		contentsList.add(new Contents(String.format("/registryObjects/registryObject[%d]", fileCount), ""));
		contentsList.add(new Contents(String.format("/registryObjects/registryObject[%d]/key[1]", fileCount), id));
		
		List<String> polygonCoordinates = getPolygonCoordinates(domHelper);
		int polygonCount = 0;
		for(String coordinates : polygonCoordinates){
			
			polygonCount++;
			
			String spatialTypeXpath = String.format("/registryObjects/registryObject[%d]/coverage[1]/spatial[%d]/@type", fileCount, polygonCount);
			String spatialTypeValue = "kmlPolyCoords";
			
			contentsList.add(new Contents(spatialTypeXpath, spatialTypeValue));
			
			String spatialXpath = String.format("/registryObjects/registryObject[%d]/coverage[1]/spatial[%d]", fileCount, polygonCount);
			
			contentsList.add(new Contents(String.format(spatialXpath, fileCount, polygonCount), coordinates));
		}
		
		xmlContentsSpatialPerKML.put(fileCount, contentsList);
		
		return xmlContentsSpatialPerKML;
		
	}
	
	private String getRegionFromFileName(final String fileName) throws Exception{
		
		// Get the region number string from the start of the file name before the underscore
		assert(fileName != null);
		assert(!fileName.isEmpty());
		
		assert(fileName.contains("_"));
		if(!fileName.contains("_")){
			throw new Exception("Expecting \'_\' in name to determine region number, e.g. Region1_xhurwhreh.xml");
		}
		
		String[] splitStrings = fileName.split("_");
		assert(splitStrings.length > 0);
		return splitStrings[0];
	}
	
	private String getRegion(final DOMHelper domHelper) throws Exception{
		
		List<String> regionList = domHelper.contentListFromPath("//*[local-name()='SimpleData'][@name='Region']");
		//String region = domHelper.contentFromPath("//*[local-name()='Document' and namespace-uri()='http://www.opengis.net/kml/2.2']");
		if(regionList.size() != 1){
			throw new Exception("Cannot determine region from list of size "+regionList.size());
		}
		
		return regionList.get(0);
	}
	
	private String getIdFromRegion(final String region) throws Exception{
		
		if(!s_regionIdMap.containsKey(region)){
			throw new Exception("No id for region "+region);
		}
		
		String id = s_regionIdMap.get(region);
		
		System.out.println("Found id "+id+" for region "+region);
		return id;
		
	}
	
	private String getIdFromRegionNumber(final String regionNumber) throws Exception{
		
		if(!s_regionNumberIdMap.containsKey(regionNumber)){
			throw new Exception("No id for region "+regionNumber);
		}
		
		String id = s_regionNumberIdMap.get(regionNumber);
		
		System.out.println("Found id "+id+" for region "+regionNumber);
		return id;
		
	}
	
	
	private List<String> getPolygonCoordinates(final DOMHelper domHelper) throws Exception{
		
		List<String> polygonCoordinates = new ArrayList<String>();
		
		NodeList polygonList = domHelper.getDocumentElementListNS("//*[local-name()='Polygon']/*[local-name()='outerBoundaryIs']/*[local-name()='LinearRing']/*[local-name()='coordinates']");
		assert(polygonList.getLength() > 0);
		for(int i = 0; i < polygonList.getLength(); i++){
		//for(int i = 0; i < 1; i++){
			Node coordinateNode = polygonList.item(i);
			assert(polygonList != null);
			String coordinates = roundCoordinates(coordinateNode.getTextContent());
			assert(coordinates != null);
			assert(!coordinates.isEmpty());
			polygonCoordinates.add(coordinates);
		}
		
		return polygonCoordinates;
		
	}
	
	private String roundCoordinates(final String coordinates){

		assert(coordinates != null);
		assert(coordinates.length() > 0);
		
		String roundedCoordinates = "";
		
		assert(coordinates.contains(" "));
		String[] coordinateSequenceList = coordinates.split(" ");
		assert(coordinateSequenceList.length > 0);
		System.out.println("Split coordinates on ' ' to get "+coordinateSequenceList.length+" entries");
		for(int k = coordinateSequenceList.length - 1; k >= 0; --k){
			
			String coordinateSequence = coordinateSequenceList[k];
			
			assert(coordinateSequence.contains(","));
			String[] coordinateList = coordinateSequence.split(",");
			assert(coordinateList.length > 0);
			System.out.println("Split coordinates on ',' to get "+coordinateList.length+" entries - "+(k+1)+" remaining");
			
			for(int i = coordinateList.length-1; i >= 0; i--){
				String coordinateStr = coordinateList[i];
				assert(coordinateStr != null);
				assert(coordinateStr.length() > 0);
				float coordinate = Float.parseFloat(coordinateStr);
				coordinateList[i] = String.format("%.4f", coordinate);
			}
			
			for(int j = 0; j < coordinateList.length; j++){
				assert(coordinateList[j] != null);
				assert(coordinateList[j].length() > 0);
				roundedCoordinates += coordinateList[j];
				if(j < coordinateList.length-1){
					roundedCoordinates += ",";
				}
			}
			
			if(k > 0){
				roundedCoordinates += " ";
			}
		}
		
		return roundedCoordinates;
	}
	
}
